// Copyright (C) 2022 即时通讯网(52im.net) & Jack Jiang.
// The RainbowChat Project. All rights reserved.
//
// 【本产品为著作权产品，合法授权后请放心使用，禁止外传！】
// 【本次授权给：<广西木子科技有限公司>，授权编号：<NT220402151538>，代码指纹：<A.648883738.885>，技术对接人微信：<ID: Lingmuziyi>】
// 【授权寄送：<收件：李先生、地址：南宁市科园西十路11号国电智能大厦1101F、电话：17736659550、邮箱：yingshashou@vip.qq.com>】
//
// 【本系列产品在国家版权局的著作权登记信息如下】：
// 1）国家版权局登记名(简称)和权证号：RainbowChat    （证书号：软著登字第1220494号、登记号：2016SR041877）
// 2）国家版权局登记名(简称)和权证号：RainbowChat-Web（证书号：软著登字第3743440号、登记号：2019SR0322683）
// 3）国家版权局登记名(简称)和权证号：RainbowAV      （证书号：软著登字第2262004号、登记号：2017SR676720）
// 4）国家版权局登记名(简称)和权证号：MobileIMSDK-Web（证书号：软著登字第2262073号、登记号：2017SR676789）
// 5）国家版权局登记名(简称)和权证号：MobileIMSDK    （证书号：软著登字第1220581号、登记号：2016SR041964）
// * 著作权所有人：江顺/苏州网际时代信息科技有限公司
//
// 【违法或违规使用投诉和举报方式】：
// 联系邮件：jack.jiang@52im.net
// 联系微信：hellojackjiang
// 联系QQ号：413980957
// 授权说明：http://www.52im.net/thread-1115-1-1.html
// 官方社区：http://www.52im.net
package com.x52im.rainbowchat.http.logic.dto;

import java.util.Observer;

import com.eva.epc.common.util.CommonUtils;

/**
 * 用户个人信息封装类。
 * <p>
 * 本类中的大部分字段意义以数据字典中“用户信息/MISSU_USERS”表保持一致。
 * <p>
 * <b>特别说明</b>：<font color="red">由于历史原因，本类的命名不够规范，以后的版本中或将重构为“UserInfo”类名！</font>
 *
 * @author Jack Jiang(http://www.52im.net/space-uid-1.html)
 * @since 1.0
 */
public class RosterElementEntity implements java.io.Serializable {
    /**
     * RainbowChat中约定uid为"-1"表示默认的无效用户uid.
     */
    public final static String DEFAULT_INVALID_UID_VALUE = "-1";

    /**
     * 用户在线状态常量：在线
     */
    public final static int LIVE_STATUS_ONLINE = 1;
    /**
     * 用户在线状态常量：离线
     */
    public final static int LIVE_STATUS_OFFLINE = 0;

    /**
     * 用户性别常量：男
     */
    public final static String SEX_MAN = "1";
    /**
     * 用户性别常量：女
     */
    public final static String SEX_WOMAN = "0";

    /*
     * ===========【说明】_ex1至_ex10为保留字段，以便未来系统更新时备用，目的在于因使用的是java序列化对象，因而
     * 理论上来讲如重大变更，KLink正式版发布后，本类将不应改变（否则客户端将会序列化对象不一致的错误），
     * 如有新字段需求则利用目前的保留字段来实现之！ */

    /**
     * 本字段当前仅用作服务端转发加好友请求（给B）时存放“验证说明文本”使用（包括离线时的好友请求）.
     *
     * @since 2.2
     */
    // 注意：_如“ex1”这种首字母带下划线的形式，fastjson转json时会忽略此字段！
    protected String ex1;

    /**
     * 本字段当前仅用作服务端转发加好友请求（给B）时存放“加好友请求发起时间戳”使用（包括离线时的好友请求）.
     *
     * @since 4.2
     */
    protected String ex10;

    /**
     * 保留字段11：留作协议升级时备用，生产环境下备用字段将能在协议升级时起到兼容旧版本的作用。
     */
    protected String ex11;
    /**
     * 保留字段12：留作协议升级时备用，生产环境下备用字段将能在协议升级时起到兼容旧版本的作用。
     */
    protected String ex12;
    /**
     * 保留字段13：留作协议升级时备用，生产环境下备用字段将能在协议升级时起到兼容旧版本的作用。
     */
    protected String ex13;
    /**
     * 保留字段14：留作协议升级时备用，生产环境下备用字段将能在协议升级时起到兼容旧版本的作用。
     */
    protected String ex14;
    /**
     * 保留字段15：留作协议升级时备用，生产环境下备用字段将能在协议升级时起到兼容旧版本的作用。
     */
    protected String ex15;

    /**
     * 本字段用于控制Android客户端的版本。作用是当出现某致命bug或重要功能时，
     * 可以强制要求用户更新，否则将无法登陆进APP。
     * <p>
     * <b>用法是：</b><br>
     * * 当本字段为空时，表示不开启强制更新，否由开启强制更新；<br>
     * * 当客户端版本小于本次强制版本号时，客户端将会被强制要求更新，更新说明即是 {@link #ex14}所指明的内容。
     * <p>
     * <b>补充说明：</b><br>
     * 本字段值为null或整数字符串，版本号对应于Android端的AndroidManifest.xml文件中定义的versionCode。
     */
    protected String mustVersion4A;
    /**
     * 本字段配合 {@link #mustVersion4A} 完成强制Android端版本更新的控制。
     * <p>
     * 当开启强制客户端更新时，客户端会将此字段内容显示在UI上，提升用户体验。
     */
    protected String mustVersionDesc4A;

    /**
     * 存放于文件服务器的用户头像文件名。
     * <p>
     * 用户客户端缓存时使用，因为用户头像读取的HTTP服务URL并不是静态地址，而是复杂的动态查询URL，
     * 在缓存文件时就无法通过URL通取到文件名称，所以本参数的作用就是缓存时用于文件名称哦）。
     * <p>
     * 详见数据字典中“用户信息/MISSU_USERS”表的设计说明。
     */
    protected String userAvatarFileName;

    /**
     * 存放用户心情（60个字符哦）。
     * <p>
     * 详见数据字典中“用户信息/MISSU_USERS”表的设计说明。
     */
    protected String whatsUp;

    /**
     * 存放该用户允许的最多好友个数。
     * <p>
     * 说明：本字段存放的是String表示的整数。详见数据字典中
     * “用户信息/MISSU_USERS”表的设计说明。
     *
     * @since 2.0
     */
    protected String maxFriend;

    /**
     * 存放该用户的个人其它说明文字。
     * <p>
     * 详见数据字典中“用户信息/MISSU_USERS”表的设计说明。
     *
     * @since 2.5
     */
    protected String userDesc;

    /**
     * 存放该用户的用户类型（无符号整数）。
     * <p>
     * 本字段目前主要用于区分普通IM用户和公司运营后台用户。具体意义详见
     * 数据字典中表“用户信息/MISSU_USERS”中user_type字段的定义。
     *
     * @since 2.5.1
     */
    protected String userType;

    /**
     * 本字段为RainbowChat系统中的用户唯id，是全系统的唯一标识。
     * <p>
     * 无论用户登陆时使用什么（可能是邮件地址、手机号、或者直接像qq一样用唯一id号），
     * 此id在任何情况下都是一个用户的唯一合法身份标识。
     * <p>
     * 为配合RainbowChat升级MobileIMSDK v3时而增加，本对象如果是由登陆接口返回，则将
     * 随后与 {@link #token} 一起在返回到客户端后，分别作为loginUserId和loginToken
     * 来登陆连接IM服务器之用。
     */
    protected String user_uid;
    /**
     * 用户的邮箱地址。
     * <p>
     * 详见数据字典中“用户信息/MISSU_USERS”表的设计说明。
     */
    protected String user_mail;

    protected String phone;

    public String getIs_realname() {
        return is_realname;
    }

    public void setIs_realname(String is_realname) {
        this.is_realname = is_realname;
    }

    protected String is_realname;

    public String getPay_psw() {
        return pay_psw;
    }

    public void setPay_psw(String pay_psw) {
        this.pay_psw = pay_psw;
    }

    protected String pay_psw;


    /**
     * 用户的昵称。
     * <p>
     * 详见数据字典中“用户信息/MISSU_USERS”表的设计说明。
     */
    protected String nickname;
    /**
     * 用户的性别。
     * <p>
     * 详见数据字典中“用户信息/MISSU_USERS”表的设计说明。
     */
    protected String user_sex;
    /**
     * 用户的注册时间。
     * <p>
     * 详见数据字典中“用户信息/MISSU_USERS”表的设计说明。
     */
    protected String register_time;

    /**
     * 实际存放的是数据库表missu_users中的latest_login_time2字段。<br>
     * 说明：本字段存放的是String表示的long整数.
     * <p>
     * 详见数据字典中“用户信息/MISSU_USERS”表的设计说明。
     *
     * @since 2.0
     */
    protected String latest_login_time;

    /**
     * 用户最近登陆ip。
     * <p>
     * 详见数据字典中“用户信息/MISSU_USERS”表的设计说明。
     *
     * @since 4.5
     */
    protected String latest_login_ip;

    /**
     * 用户的在线状态：0 表示不在线，1 表示在线
     */
    protected int liveStatus = LIVE_STATUS_OFFLINE;

    /**
     * <b>用途1：用于IM的连接认证> </b>
     * <p>
     * 为了接下来客户端对接IM即时通讯框架而生成的token，主要用于安全策略，具体生成和使用方法由逻辑层定义。
     * 本字段仅在从登陆接口返回时有意义，其它情况下无意义。
     * <br>
     * 截止20170216日止，本字段暂作保留字段，未来在架构优化和升级和，在服务端性能能得到保证的前提下再启
     * 用此token的验证不迟。
     * <p>
     * 本字段为配合RainbowChat升级MobileIMSDK v3时而增加，将与 {@link #user_uid} 一起在返回到客户端
     * 后，分别作为loginUserId和loginToken来登陆连接IM服务器之用。<br>
     * TODO 为了便于解偶和对接IM实时框架的理解，未来可以考虑将http的登际认证接口独立为SSO单点登陆接口，
     * 而与SSO接口配合使用会让MobileIMSDK v3的理解更为直观和简单。
     * <p>
     * <b>用途2：用于HTTP REST接口调用时的合法身份标识> </b>
     * <p>
     * 基于HTTP REST接口调用的安全考虑，此token建议每次调用rest接口时带上，以便rest服务端检查此次rest
     * 表求的合法性。
     *
     * @since 4.0
     */
    protected String token = null;

    /**
     * 本对象不需要序列化（因为仅用于客户端使用，与服务端无关）：用于保存好友的上下线通知观察者哦（全局只有一个这样的观察者）.
     * <b>说明：</b>本观察者被通知时，update方法的data参数收到的将是一个String[]数组：元素0是昵称、元素1是上下线状态、元素2是uid.
     *
     * @see #LIVE_STATUS_ONLINE
     * @see #LIVE_STATUS_OFFLINE
     */
    protected transient static Observer liveStatusChangeObs = null;

    /**
     * 好友备注。
     * <p>
     * <b>注：</b>本字段对应于数据库表“missu_roster”中的“remark”字段（详见数据库字典），
     * 当前仅用于客户端查询当前仅用于客户端查询好友列表数据时使用，其它情况下本字段无意义！
     *
     * @since 7.3
     */
    protected String friendRemark;
    /**
     * 好友手机号。
     * <p>
     * <b>注：</b>本字段对应于数据库表“missu_roster”中的“mobile_num”字段（详见数据库字典），
     * 当前仅用于客户端查询当前仅用于客户端查询好友列表数据时使用，其它情况下本字段无意义！
     *
     * @since 7.3
     */
    protected String friendMobileNum;
    /**
     * 好友更多描述。
     * <p>
     * <b>注：</b>本字段对应于数据库表“missu_roster”中的“more_desc”字段（详见数据库字典），
     * 当前仅用于客户端查询当前仅用于客户端查询好友列表数据时使用，其它情况下本字段无意义！
     *
     * @since 7.3
     */
    protected String friendMoreDesc;
    /**
     * 好友相关图片、名片（存放的是文件名，详见数据库字典中的字段说明） 。
     * <p>
     * <b>注：</b>本字段对应于数据库表“missu_roster”中的“pic_file_name”字段（详见数据库字典），
     * 当前仅用于客户端查询当前仅用于客户端查询好友列表数据时使用，其它情况下本字段无意义！
     *
     * @since 7.3
     */
    protected String friendPicFileName;

    public String getUser_uid() {
        return user_uid;
    }

    public RosterElementEntity setUser_uid(String user_uid) {
        this.user_uid = user_uid;
        return this;
    }

    public String getUser_mail() {
        return user_mail;
    }

    public RosterElementEntity setUser_mail(String user_mail) {
        this.user_mail = user_mail;
        return this;
    }

    public String getNickname() {
        return nickname;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    /**
     * 获取好友的备注昵称，当设置了好友备注时则返回的是备注，否则返回的是原昵称。
     *
     * @return 返回好友备注优先的昵称
     * @see #friendRemark
     * @see #nickname
     */
    public String getNickNameWithRemark() {
        if (CommonUtils.isStringEmpty(this.friendRemark, true))
            return this.nickname;
        return this.friendRemark;
    }

    public RosterElementEntity setNickname(String nickname) {
        this.nickname = nickname;
        return this;
    }

    public String getUser_sex() {
        return user_sex;
    }

    public RosterElementEntity setUser_sex(String user_sex) {
        this.user_sex = user_sex;
        return this;
    }

    public String getRegister_time() {
        return register_time;
    }

    public void setRegister_time(String register_time) {
        this.register_time = register_time;
    }

    public String getLatest_login_time() {
        return latest_login_time;
    }

    public void setLatest_login_time(String latest_login_time) {
        this.latest_login_time = latest_login_time;
    }

    public int getLiveStatus() {
        return liveStatus;
    }

    public RosterElementEntity setLiveStatus(int liveStatus) {
        this.liveStatus = liveStatus;

        // 并把上下线状态改变通知给观察者
        if (RosterElementEntity.getLiveStatusChangeObs() != null)
            RosterElementEntity.getLiveStatusChangeObs().update(null
                    , new String[]{this.nickname, "" + liveStatus, user_uid});

        return this;
    }

    public String getToken() {
        return token;
    }

    public void setToken(String tokenforIM) {
        this.token = tokenforIM;
    }

    /**
     * 是否在线.
     *
     * @return
     */
    public boolean isOnline() {
        return this.liveStatus == LIVE_STATUS_ONLINE;
    }

    /**
     * 用户上线设定方便方法.<br>
     * 通过此方法可同时实现设置用户在线状态.
     *
     * @param user_id
     * @see #setUser_id(int)
     * @see #setLiveStatus(int)
     */
    public void online() {
        this.setLiveStatus(LIVE_STATUS_ONLINE);
    }

    /**
     * 用户下线设定方便方法.<br>
     * 通过此方法可同时实现设置用户在线状态.
     *
     * @param user_id
     * @see #setUser_id(int)
     * @see #setLiveStatus(int)
     */
    public void offline() {
        this.setLiveStatus(LIVE_STATUS_OFFLINE);
    }

    /**
     * 该用户是否男性.
     *
     * @return true表示男性，否则表示女性
     */
    public boolean isMan() {
        return SEX_MAN.equals(this.user_sex);
    }

    @Override
    public String toString() {
        return this.nickname;
    }

    //----------------------------------------------------------------------------------------- 保留字段 S
    public String getEx1() {
        return ex1;
    }

    public void setEx1(String ex1) {
        this.ex1 = ex1;
    }

    public String getMustVersion4A() {
        return mustVersion4A;
    }

    public void setMustVersion4A(String mustVersion4A) {
        this.mustVersion4A = mustVersion4A;
    }

    public String getMustVersionDesc4A() {
        return mustVersionDesc4A;
    }

    public void setMustVersionDesc4A(String mustVersionDesc4A) {
        this.mustVersionDesc4A = mustVersionDesc4A;
    }

    public String getUserAvatarFileName() {
        return userAvatarFileName;
    }

    public void setUserAvatarFileName(String userAvatarFileName) {
        this.userAvatarFileName = userAvatarFileName;
    }

    public String getWhatsUp() {
        return whatsUp;
    }

    public void setWhatsUp(String whatsUp) {
        this.whatsUp = whatsUp;
    }

    public String getMaxFriend() {
        return maxFriend;
    }

    public void setMaxFriend(String maxFriend) {
        this.maxFriend = maxFriend;
    }

    public String getUserDesc() {
        return userDesc;
    }

    public void setUserDesc(String userDesc) {
        this.userDesc = userDesc;
    }

    public String getUserType() {
        return userType;
    }

    public void setUserType(String userType) {
        this.userType = userType;
    }

    public String getLatest_login_ip() {
        return latest_login_ip;
    }

    public void setLatest_login_ip(String latest_login_ip) {
        this.latest_login_ip = latest_login_ip;
    }

    public String getEx10() {
        return ex10;
    }

    public void setEx10(String ex10) {
        this.ex10 = ex10;
    }

    public Object getEx11() {
        return ex11;
    }

    public void setEx11(String ex11) {
        this.ex11 = ex11;
    }

    public String getEx12() {
        return ex12;
    }

    public void setEx12(String ex12) {
        this.ex12 = ex12;
    }

    public String getEx13() {
        return ex13;
    }

    public void setEx13(String ex13) {
        this.ex13 = ex13;
    }

    public String getEx14() {
        return ex14;
    }

    public void setEx14(String ex14) {
        this.ex14 = ex14;
    }

    public String getEx15() {
        return ex15;
    }

    public void setEx15(String ex15) {
        this.ex15 = ex15;
    }

    public String getFriendRemark() {
        return friendRemark;
    }

    public void setFriendRemark(String friendRemark) {
        this.friendRemark = friendRemark;
    }

    public String getFriendMobileNum() {
        return friendMobileNum;
    }

    public void setFriendMobileNum(String friendMobileNum) {
        this.friendMobileNum = friendMobileNum;
    }

    public String getFriendMoreDesc() {
        return friendMoreDesc;
    }

    public void setFriendMoreDesc(String friendMoreDesc) {
        this.friendMoreDesc = friendMoreDesc;
    }

    public String getFriendPicFileName() {
        return friendPicFileName;
    }

    public void setFriendPicFileName(String friendPicFileName) {
        this.friendPicFileName = friendPicFileName;
    }

    protected RosterElementEntity doClone(RosterElementEntity newObj) {
        if (newObj != null) {
            newObj.setEx1(this.ex1);
            newObj.setEx10(this.ex10);
            newObj.setEx11(this.ex11);
            newObj.setEx12(this.ex12);
            newObj.setEx13(this.ex13);
            newObj.setEx14(this.ex14);
            newObj.setEx15(this.ex15);
            newObj.setMustVersion4A(this.mustVersion4A);
            newObj.setMustVersionDesc4A(this.mustVersionDesc4A);
            newObj.setUserAvatarFileName(this.userAvatarFileName);
            newObj.setWhatsUp(this.whatsUp);
            newObj.setMaxFriend(this.maxFriend);
            newObj.setUserDesc(this.userDesc);
            newObj.setUserType(this.userType);
            newObj.setUser_uid(this.user_uid);
            newObj.setUser_mail(this.user_mail);
            newObj.setNickname(this.nickname);
            newObj.setPhone(this.phone);
            newObj.setUser_sex(this.user_sex);
            newObj.setRegister_time(this.register_time);
            newObj.setLatest_login_time(this.latest_login_time);
            newObj.setLiveStatus(this.liveStatus);
            newObj.setToken(this.token);
            newObj.setFriendRemark(this.friendRemark);
            newObj.setFriendMobileNum(this.friendMobileNum);
            newObj.setFriendMoreDesc(this.friendMoreDesc);
            newObj.setFriendPicFileName(this.friendPicFileName);
        }
        return newObj;
    }

    /**
     * RosterElementEntity 深度对象克隆方法实现。
     *
     * @return 克隆完成后的新对象
     * @since 4.0, 20170225
     */
    @Override
    public Object clone() {
        RosterElementEntity cloneRee = new RosterElementEntity();
        return doClone(cloneRee);
    }


    //----------------------------------------------------------------------------------------- 保留字段 E

    public static void setLiveStatusChangeObs(Observer liveStatusChangeObs) {
        RosterElementEntity.liveStatusChangeObs = liveStatusChangeObs;
    }

    public static Observer getLiveStatusChangeObs() {
        return liveStatusChangeObs;
    }
}
